using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Xna.Framework.Graphics.PackedVector;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace Scurvy.Media
{
    /// <summary>
    /// Streams the video from the file stream that the content manager opens
    /// </summary>
    public class VideoStream : Video
    {
        #region Private Fields

        private Texture2D _texture;
        private int numberOfFrames;
        private double frameRate;
        private Stream _stream;
        private BinaryReader reader;
        private long _streamBeginIndex;
        private int _lastFrame = 0;
        private byte[] _data;
        private Bgr565[] _pixels;
        
        #endregion

        internal VideoStream(ContentReader creader, int numberOfFrames, double frameRate, int height, int width, GraphicsDevice device)
            : base(numberOfFrames, frameRate)
        {
            Stream stream = creader.BaseStream;
            _streamBeginIndex = stream.Position;

            GraphicsDeviceManager gdm = (GraphicsDeviceManager)creader.ContentManager.ServiceProvider.GetService(typeof(IGraphicsDeviceManager));
            
            _texture = new Texture2D(gdm.GraphicsDevice, width, height, 1, ResourceUsage.None, SurfaceFormat.Bgr565, ResourceManagementMode.Automatic);
            _stream = stream;
            this.numberOfFrames = numberOfFrames;
            this.frameRate = frameRate;

            reader = new BinaryReader(stream);

            LoadNextFrame();
        }

        /// <exception cref="InvalidContentManagerException">This exception will be thrown
        /// if the incorrect type of content manager was used to instantiate this video.</exception>
        public override Microsoft.Xna.Framework.Graphics.Texture2D CurrentTexture
        {
            get 
            {
                try
                {
                    if (_lastFrame != this.CurrentIndex)
                    {
                        if (_lastFrame > this.CurrentIndex)
                        {
                            this._stream.Seek(_streamBeginIndex, SeekOrigin.Begin);
                        }

                        _lastFrame = this.CurrentIndex;
                        LoadNextFrame();
                    }
                    return _texture;
                }
                catch (ObjectDisposedException ode)
                {
                    throw new InvalidContentManagerException(ode);
                }
            }
        }

        private void LoadNextFrame()
        {
            int frameSize = reader.ReadInt32();
            if (_data == null)
            {
                _data = new byte[frameSize];
                _pixels = new Bgr565[frameSize / 2];
            }
            _stream.Read(_data, 0, frameSize);

            int currentPixel = 0;
            for (int i = 0; i < _data.Length; i += 2)
            {
                _pixels[currentPixel].PackedValue = (ushort)((_data[i + 1] << 8) + _data[i]);

                currentPixel++;
            }
            
            _texture.SetData<Bgr565>(_pixels);
        }

        
    }
}
